using System;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using TerrainContent;

namespace SAM3D
{
    /// <summary>
    ///   This is the main type for your game
    /// </summary>
    public class Game1 : Game
    {
        private readonly GraphicsDeviceManager graphics;
        private MeshObject _plane;
        private Terrain _terrain;
        private Camera camera;
        private SpriteBatch spriteBatch;
        private Model testPlane;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        ///   Allows the game to perform any initialization it needs to before starting to run.
        ///   This is where it can query for any required services and load any non-graphic
        ///   related content.  Calling base.Initialize will enumerate through any components
        ///   and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            camera = new Camera(this,
                                new Transform
                                    {
                                        Position = Vector3.Up*2 + Vector3.Backward*4,
                                        Scale = Vector3.One
                                    });
            new CameraManager(this).Add(camera);


            var terrData = Content.Load<TerrainData>("magyarorszag domb");
            _terrain = new Terrain(this, terrData);
            Components.Add(_terrain);

            _plane = (new MeshObject(this,
                                     new Transform(),
                                     terrData.FullMesh));

            testPlane = Content.Load<Model>("terrainPlane");
            base.Initialize();
        }

        /// <summary>
        ///   LoadContent will be called once per game and is the place to load
        ///   all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
        }

        /// <summary>
        ///   UnloadContent will be called once per game and is the place to unload
        ///   all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        ///   Allows the game to run logic such as updating the world,
        ///   checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name = "gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                Exit();

            //camera.Transform.Position = new Vector3(0, (float)(Math.Sin(gameTime.TotalGameTime.TotalSeconds/4) + 1) * 10, 0) + Vector3.Backward * 4;
            KeyboardState state = Keyboard.GetState();
            if (state.IsKeyDown(Keys.Up))
                camera.Transform.Position += Vector3.Forward*4*(float) gameTime.ElapsedGameTime.TotalSeconds;
            if (state.IsKeyDown(Keys.Down))
                camera.Transform.Position += Vector3.Backward*4*(float) gameTime.ElapsedGameTime.TotalSeconds;
            if (state.IsKeyDown(Keys.D))
                camera.Transform.Position += Vector3.Right*4*(float) gameTime.ElapsedGameTime.TotalSeconds;
            if (state.IsKeyDown(Keys.A))
                camera.Transform.Position += Vector3.Left*4*(float) gameTime.ElapsedGameTime.TotalSeconds;
            if (state.IsKeyDown(Keys.W))
                camera.Transform.Position += Vector3.Up*(float) gameTime.ElapsedGameTime.TotalSeconds;
            if (state.IsKeyDown(Keys.S))
                camera.Transform.Position += Vector3.Down*(float) gameTime.ElapsedGameTime.TotalSeconds;
            if (state.IsKeyDown(Keys.Right))
                camera.Transform.Rotation *= Quaternion.CreateFromYawPitchRoll(
                    -MathHelper.PiOver2*
                    (float) gameTime.ElapsedGameTime.TotalSeconds, 0, 0);
            if (state.IsKeyDown(Keys.Left))
                camera.Transform.Rotation *= Quaternion.CreateFromYawPitchRoll(
                    MathHelper.PiOver2*
                    (float) gameTime.ElapsedGameTime.TotalSeconds, 0, 0);
            if (state.IsKeyDown(Keys.Q))
                camera.Transform.Rotation *= Quaternion.CreateFromYawPitchRoll(0,
                                                                               -MathHelper.PiOver2*
                                                                               (float)
                                                                               gameTime.ElapsedGameTime.TotalSeconds, 0);
            if (state.IsKeyDown(Keys.Z))
                camera.Transform.Rotation *= Quaternion.CreateFromYawPitchRoll(0,
                                                                               MathHelper.PiOver2*
                                                                               (float)
                                                                               gameTime.ElapsedGameTime.TotalSeconds, 0);


            if (state.IsKeyDown(Keys.L))
                _terrain.Morph -= 1f * (float)gameTime.ElapsedGameTime.TotalSeconds; 
            if (state.IsKeyDown(Keys.O))
                _terrain.Morph += 1f * (float)gameTime.ElapsedGameTime.TotalSeconds;

            Console.WriteLine("Full: " + _terrain.PickedNodes.Count);
            Console.WriteLine("Partial: " + _terrain.PickedPartialNodes.Count);
            Console.WriteLine("Altitude: " + camera.Transform.Position.Y);

            base.Update(gameTime);
        }

        /// <summary>
        ///   This is called when the game should draw itself.
        /// </summary>
        /// <param name = "gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            base.Draw(gameTime);


            if (Keyboard.GetState().IsKeyDown(Keys.C))
            {
                using (var screenshot = new Texture2D(graphics.GraphicsDevice,
                                                      graphics.GraphicsDevice.PresentationParameters.BackBufferWidth,
                                                      graphics.GraphicsDevice.PresentationParameters.BackBufferHeight))
                {
                    Color[] bbDat = new Color[screenshot.Width * screenshot.Height];
                    graphics.GraphicsDevice.GetBackBufferData<Color>(bbDat);
                    screenshot.SetData(bbDat);
                    screenshot.SaveAsPng(File.Open("scrshot.png", FileMode.Create), screenshot.Width, screenshot.Height);
                }
            }
        }
    }
}